package org.sxp.common.exception;

import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import org.sxp.common.web.XpContextHolder;
import org.sxp.common.web.LogContext;
import org.sxp.common.web.WrapperResponse;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * @author shenxingping
 * @date 2021/01/29
 */
public class XPHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
    private Logger log = LoggerFactory.getLogger(XPHandlerExceptionResolver.class);
    private String viewType = "json";
    private String defaultErrorView;
    private String defaultErrorMessage;
    private Map<Integer, String> exceptionMappings = new HashMap();
    private String LOG_CONTEXT_KEY = "_logContext";
    @Autowired
    ExceptionSeq exceptionSeq;

    public XPHandlerExceptionResolver() {
    }
    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView mv = null;
        Integer errorCode = WrapperResponse.FAIL;
        LogContext logContext = (LogContext) XpContextHolder.getContext().getProperty(this.LOG_CONTEXT_KEY);
        String traceID = "";
        String traceInfo = "[hsafException]";
        if (logContext != null && logContext.getTraceID() != null) {
            traceID = logContext.getTraceID();
            traceInfo = traceInfo + "[traceID:" + traceID + "]";
        }

        String exseq = this.exceptionSeq.getExceptionSeq();
        if (ex instanceof AppException) {
            int code = ((AppException)ex).getCode();
            errorCode = code;
            this.log.warn(traceInfo + ",异常流水号exseq=" + exseq + ",错误信息:" + ex.getMessage());
        } else if (ex.getCause() == null) {
            this.log.error(traceInfo + ",异常流水号exseq=" + exseq + ",错误信息:" + ex.getMessage(), ex);
        } else {
            this.log.error(traceInfo + ",异常流水号exseq=" + exseq + ",错误信息:" + ex.getMessage(), ex.getCause());
        }

        if (this.viewType.equalsIgnoreCase("page")) {
            String viewName = this.defaultErrorView;
            if (this.exceptionMappings != null && this.exceptionMappings.containsKey(errorCode)) {
                viewName = (String)this.exceptionMappings.get(errorCode);
            }

            mv = new ModelAndView();
            mv.setViewName(viewName);
        } else {
            mv = new ModelAndView(new MappingJackson2JsonView());
        }

        mv.addObject("code", errorCode);
        if (ex instanceof AppException && ex.getMessage() != null && ex.getMessage().length() > 0) {
            mv.addObject("msg", ex.getMessage() + ",异常流水号:" + exseq);
        } else if(ex instanceof UnauthorizedException){
            mv.addObject("msg", ex.getMessage() + ",异常流水号:" + exseq);
        }else if (this.defaultErrorMessage != null && !this.defaultErrorMessage.equals("")) {
            mv.addObject("msg", this.defaultErrorMessage + ",异常流水号:" + exseq);
        } else {
            mv.addObject("msg", ex.getMessage() + ",异常流水号:" + exseq);
        }

        return mv;
    }

    public void setViewType(String viewType) {
        this.viewType = viewType;
    }

    public void setDefaultErrorView(String defaultErrorView) {
        this.defaultErrorView = defaultErrorView;
    }

    public void setExceptionMappings(Map<Integer, String> exceptionMappings) {
        this.exceptionMappings.putAll(exceptionMappings);
    }

    public void addExceptionMappings(Integer errorCode, String errorView) {
        this.exceptionMappings.put(errorCode, errorView);
    }

    public void setDefaultErrorMessage(String defaultErrorMessage) {
        this.defaultErrorMessage = defaultErrorMessage;
    }
}
